Imports System
Imports System.Data
Imports System.Collections.Generic
Imports System.Reflection
Imports System.Web

Imports Framework
'Table-Row Class (Customisable half)
Partial Public Class CAudit_Error

#Region "Constants"
    Private Const VIEW_UNIQUE As String = "vwAudit_Error"
#End Region

#Region "Constructors (Public)"
    'Default Connection String
    Public Sub New()
        MyBase.New()
    End Sub
    Public Sub New(errorID As Integer)
        MyBase.New(errorID)
    End Sub
    
    'Alternative Connection String
    Public Sub New(ByVal dataSrc As CDataSrc)
        MyBase.New(dataSrc)
    End Sub
    Public Sub New(ByVal dataSrc As CDataSrc, errorID As Integer)
        MyBase.New(dataSrc, errorID)
    End Sub

    'Transactional (shares an open connection)
    Protected Friend Sub New(ByVal dataSrc As CDataSrc, ByVal errorID As Integer, ByVal txOrNull As IDbTransaction)
        MyBase.New(dataSrc, errorID, txOrNull)
    End Sub

    Public Sub New(ByVal type1 As Integer, ByVal message1 As Integer, ByVal type2 As Integer, ByVal message2 As Integer)
        Dim dt As DataTable = SelectWhere_Dataset(BuildWhereGroup(type1, message1, type2, message2), VIEW_UNIQUE).Tables(0)
        If dt.Rows.Count = 0 Then Exit Sub
        Me.Load(dt.Rows(0))
    End Sub
#End Region

#Region "Default Values"
    Protected Overrides Sub InitValues_Custom()
        'Custom default values (e.g. DateCreated column)
        m_errorDateCreated = DateTime.Now
        
        'Member variables (e.g. for child collections)
        
    End Sub
#End Region

#Region "Default Connection String"
    Protected Overrides Function DefaultDataSrc() As CDataSrc
        Return CDataSrc.Default
    End Function
#End Region

#Region "Members"
    'Foreign Keys   

    'Child Collections  

    'Xml Data (as high-level objects)

#End Region

#Region "Properties - Relationships"    
    'Relationships - Foriegn Keys (e.g parent)

    'Relationships - Collections (e.g. children)

#End Region

#Region "Properties - Customisation"
    Public ReadOnly Property FullUrl() As String
        Get
            Return String.Concat("http://", Me.ErrorWebsite, Me.ErrorUrl)
        End Get
    End Property
    Public ReadOnly Property ErrorMessageHtml() As String
        Get
            Return HtmlEncode(ErrorMessage)
        End Get
    End Property
    Public ReadOnly Property ErrorInnerMessageHtml() As String
        Get
            Return HtmlEncode(ErrorInnerMessage)
        End Get
    End Property

    Private Shared Function HtmlEncode(ByVal s As String) As String
        If String.IsNullOrEmpty(s) Then
            Return String.Empty
        End If
        Return s.Replace(vbCr & vbLf, "<br>")
    End Function
#End Region

#Region "Save/Delete Overrides"
    Public Overrides Sub Save(ByVal txOrNull As System.Data.IDbTransaction)
        If Not IsNothing(ErrorType) Then ErrorTypeHash = ErrorType.GetHashCode
        If Not IsNothing(ErrorMessage) Then ErrorMessageHash = ErrorMessage.GetHashCode
        If Not IsNothing(ErrorInnerType) Then ErrorInnerTypeHash = ErrorInnerType.GetHashCode
        If Not IsNothing(ErrorInnerMessage) Then ErrorInnerMessageHash = ErrorInnerMessage.GetHashCode

        MyBase.Save(txOrNull)
    End Sub
#End Region

#Region "Cloning"
    Public Function Clone(ByVal target As CDataSrc, ByVal txOrNull As IDbTransaction) As CAudit_Error ', parentId As Integer) As CAudit_Error
        'Shallow copy: Copies the immediate record, excluding autogenerated Pks
        Dim copy As New CAudit_Error(Me, target)
        copy.Save(txOrNull)

        'Deep Copy - Child Entities: Cloned children must reference their cloned parent
        'copy.SampleParentId = parentId

        'Deep Copy - Parent Entities: Cloned parents also clone their child collections
        'Me.Children.Clone(target, txOrNull, copy.ErrorID)

        Return copy
    End Function
#End Region

#Region "Custom Database Queries"
    'Dynamic sql: Use SelectWhere, SelectCount, SelectSum, SelectDistinct
    'Stored procedures: Use MakeList (cast result as CAudit_ErrorList)
    'See also the auto-generated examples (need to identify FK columns during code gen.)
    Public Function SelectGroup(ByVal pi As CPagingInfo, ByVal type1 As Integer, ByVal message1 As Integer, ByVal type2 As Integer, ByVal message2 As Integer) As CAudit_ErrorList
        Return SelectWhere(pi, BuildWhereGroup(type1, message1, type2, message2))
    End Function
    Public Function SelectGroup(ByVal type1 As Integer, ByVal message1 As Integer, ByVal type2 As Integer, ByVal message2 As Integer) As CAudit_ErrorList
        Return SelectWhere(BuildWhereGroup(type1, message1, type2, message2))
    End Function
    Public Function SelectGroup_DataSet(ByVal type1 As Integer, ByVal message1 As Integer, ByVal type2 As Integer, ByVal message2 As Integer) As DataSet
        Return SelectWhere_Dataset(BuildWhereGroup(type1, message1, type2, message2))
    End Function
    Public Function SelectGroupCount(ByVal type1 As Integer, ByVal message1 As Integer, ByVal type2 As Integer, ByVal message2 As Integer) As Integer
        Return SelectCount(BuildWhereGroup(type1, message1, type2, message2))
    End Function
    Private Function BuildWhereGroup(ByVal type1 As Integer, ByVal message1 As Integer, ByVal type2 As Integer, ByVal message2 As Integer) As CCriteriaList
        Dim where As New CCriteriaList()
        where.Add("ErrorTypeHash", type1)
        where.Add("ErrorMessageHash", message1)
        where.Add("ErrorInnerTypeHash", type2)
        where.Add("ErrorInnerMessageHash", message2)
        Return where
    End Function
    Public Function CountSimilar() As Integer
        Return SelectGroupCount(ErrorTypeHash, ErrorMessageHash, ErrorInnerTypeHash, ErrorInnerMessageHash)
    End Function
#End Region

#Region "Search - Interfaces (Select/Count/Sub/Distint Or Stored Procs)"
    'Custom (e.g build a common filter and pass to methods below)
    Public Function Search(ByVal nameOrId As String) As CAudit_ErrorList
        Return SelectSearch(New CSearchFilters(nameOrId), False)
    End Function
    Public Function Search(ByVal pi As CPagingInfo, ByVal nameOrId As String) As CAudit_ErrorList
        Return SelectSearch(pi, New CSearchFilters(nameOrId), False)
    End Function
    Public Function Search(ByVal pi As CPagingInfo, ByVal nameOrId As String, ByVal uniqueOnly As Boolean) As CAudit_ErrorList
        Return SelectSearch(pi, New CSearchFilters(nameOrId), uniqueOnly)
    End Function

    'Sample Search (paged/non-paged)
    Public Function SelectSearch(ByVal filters As CSearchFilters, ByVal uniqueOnly As Boolean) As CAudit_ErrorList
        If uniqueOnly Then
            Return SelectWhere(BuildWhere(filters), VIEW_UNIQUE)
        Else
            Return SelectWhere(BuildWhere(filters))
        End If
    End Function
    Public Function SelectSearch(ByVal pi As CPagingInfo, ByVal name As String, ByVal uniqueOnly As Boolean) As CAudit_ErrorList
        Return SelectSearch(pi, New CSearchFilters(name), uniqueOnly)
    End Function
    Public Function SelectSearch(ByVal pi As CPagingInfo, ByVal filters As CSearchFilters, ByVal uniqueOnly As Boolean) As CAudit_ErrorList
        If uniqueOnly Then pi.TableName = VIEW_UNIQUE
        Return SelectWhere(pi, BuildWhere(filters))
    End Function

    'Sample Count
    Public Overloads Function SelectCount(ByVal filters As CSearchFilters) As Integer
        Return SelectCount(BuildWhere(filters)) ', JOIN_EXPRESSION)
    End Function

    'Dataset
    Public Function SelectSearch_Dataset(ByVal name As String, ByVal uniqueOnly As Boolean) As DataSet
        Dim view As String = TABLE_NAME
        If uniqueOnly Then view = VIEW_UNIQUE
        Return SelectWhere_Dataset(BuildWhere(New CSearchFilters(name)), SelectColumns, view, OrderByColumns)
    End Function
#End Region

#Region "Search - Logic (Where Expression)"
    Private Function BuildWhere(ByVal filters As CSearchFilters) As CCriteriaList
        Dim where As New CCriteriaList 'Main expression defaults to AND logic. To mix AND/OR, use a CCriteriaGroup (parenthesis)
        With filters
            'Simple search box UI
            If Not String.IsNullOrEmpty(.NameOrId) Then
                'Interpret search string in various ways using OR
                Dim orExpr As New CCriteriaGroup(EBoolOperator.Or)

                'Special case - search by PK (assumes integer PK)
                Dim id As Integer
                If Integer.TryParse(.NameOrId, id) Then
                    orExpr.Add("ErrorID", id)
                End If

                'Search a range of string columns
                orExpr.Add("ErrorId", ESign.Like, "%" & .NameOrId & "%")
                orExpr.Add("ErrorUserName", ESign.Like, "%" & .NameOrId & "%")
                orExpr.Add("ErrorMachineName", ESign.Like, "%" & .NameOrId & "%")
                orExpr.Add("ErrorApplicationName", ESign.Like, "%" & .NameOrId & "%")

                'Conclude
                If orExpr.Group.Count > 0 Then
                    where.Add(orExpr)
                End If
            End If

            'Other search Colums
            '(customise as required)
            'If .UserID <> Integer.MinValue Then where.Add("ErrorUserID", .UserID)

        End With
        Return where
    End Function
#End Region

#Region "Search - Filters (keywords etc from UI)"
    'UI-driven collection of potential search filters e.g. 'date' could match against startdate/enddate columns
    Public Class CSearchFilters
        'Constructors (add more for common combinations, or introduce more classes)
        Public Sub New(ByVal nameOrId As String)
            Me.NameOrId = nameOrId.Trim.ToLower()
        End Sub

        'Members (filter info)
        Public NameOrId As String = String.Empty
    End Class

#End Region

#Region "ToXml"
    Protected Overrides Sub ToXml_Custom(ByVal w As System.Xml.XmlWriter)
        'Store(w, "Example", Me.Example)
    End Sub
#End Region

#Region "Static"
    Public Shared Function Log(ByVal ex As Exception) As Integer
        Return Log(ex, Nothing, Environment.UserName)
    End Function
    Public Shared Function Log(ByVal ex As Exception, ByVal userId As String, ByVal userName As String) As Integer
        Dim a As Assembly = Assembly.GetEntryAssembly()
        If IsNothing(a) Then a = Assembly.GetCallingAssembly()
        If IsNothing(a) Then a = Assembly.GetExecutingAssembly
        Return Log(ex, userId, userName, a)
    End Function
    Public Shared Function Log(ByVal ex As Exception, ByVal userId As String, ByVal userName As String, ByVal assembly As Assembly) As Integer
        Try
            Dim e As New CAudit_Error()

            'User info
            e.ErrorUserID = userId
            e.ErrorUserName = CUtilities.Truncate(userName, 50)

            'Assembly info
            Dim assName As AssemblyName = assembly.GetName()
            If Not IsNothing(assName) Then
                e.ErrorApplicationName = CUtilities.Truncate(assName.Name, 50)
                e.ErrorApplicationVersion = CUtilities.Truncate(assName.Version.ToString(), 50)
            End If

            'Website info
            Dim c As HttpContext = HttpContext.Current
            If c IsNot Nothing Then
                e.ErrorUrl = CUtilities.Truncate(c.Request.RawUrl, 2000)
                e.ErrorWebsite = CUtilities.Truncate(c.Request.Url.Host, 200)
                e.ErrorMachineName = CUtilities.Truncate(c.Server.MachineName, 50)
            Else
                e.ErrorMachineName = Environment.MachineName
                Try
                    e.ErrorUrl = CUtilities.Truncate(Environment.CommandLine.Replace("""", ""), 2000)
                    e.ErrorWebsite = IO.Path.GetFileName(Environment.CommandLine.Replace("""", ""))
                Catch
                End Try
            End If

            'Exception info
            e.ErrorType = CUtilities.Truncate(ex.[GetType]().ToString(), 200)
            e.ErrorMessage = CUtilities.Truncate(ex.Message, 3000)
            e.ErrorStacktrace = CUtilities.Truncate(ex.StackTrace, 4000)

            'Inner exceptions
            If ex.InnerException IsNot Nothing Then
                ex = ex.InnerException
                e.ErrorInnerType = CUtilities.Truncate(ex.[GetType]().ToString(), 200)
                e.ErrorInnerMessage = CUtilities.Truncate(ex.Message, 3000)
                e.ErrorInnerStacktrace = CUtilities.Truncate(ex.StackTrace, 4000)

                'Deep exceptions
                If Not IsNothing(ex.InnerException) Then Log(ex.InnerException, userId, userName, assembly)
            End If

            e.Save()
            Return e.ErrorID
        Catch
            Return Integer.MinValue
        End Try
    End Function
#End Region
End Class
